/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alexandre-barbosa.com/

 Copyright (c) 2008 Alexandre Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#pragma warning ( disable : 4996 )
#pragma warning ( disable : 4800 )
#pragma warning ( disable : 4355 )
#pragma warning ( disable : 4267 )
#endif

#include <boost/spirit/include/classic_core.hpp>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>

#include "auxiliar.h"
#include "cnome.h"

namespace cnome {
cpp const cnome_p;
}

using namespace boost::spirit::classic;
using namespace boost::wave;
using namespace cnome;
using namespace std;

void cnome_invalid_parameter_handler(const wchar_t * a, const wchar_t * b, const wchar_t * c, unsigned int d, uintptr_t e)
{
	throw exception("cnome_invalid_parameter_handler");
}

///////////////////////////////////////////////////////////////////////////////
// main entry point
int main(int argc, char *argv[]) {
	if (2 != argc) {
		std::cerr << "Usage: cnome <cpp file>" << std::endl;
		return -1;
	}
	_set_invalid_parameter_handler(cnome_invalid_parameter_handler);

	// current file position is saved for exception handling
	boost::wave::util::file_position_type current_position;

	try {
		//  Open and read in the specified input file.
		std::ifstream instream(argv[1]);
		std::string instring;

		if (!instream.is_open()) {
			std::cerr << "Could not open input file: " << argv[1] << std::endl;
			return -2;
		}
		instream.unsetf(std::ios::skipws);
		instring = std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
			std::istreambuf_iterator<char>());

		// The preprocessor iterator shouldn't be constructed directly. It is 
		// to be generated through a wave::context<> object. This wave:context<> 
		// object is to be used additionally to initialize and define different 
		// parameters of the actual preprocessing (not done here).
		//
		// The preprocessing of the input stream is done on the fly behind the 
		// scenes during iteration over the context_t::cnome_iterator stream.
		context_t ctx (instring.begin(), instring.end(), argv[1]);
		readConfig(ctx);
		// analyze the input file
		cnome_iterator first = ctx.begin();
		cnome_iterator last = ctx.end();
		parse_info<cnome_iterator> info = parse(first, last, cnome_p);

		if (info.full)
		{
			cout << "-------------------------\n";
			cout << "Parsing succeeded\n";
			cout << "-------------------------\n";
		}
		else
		{
			cout << "-------------------------\n";
			cout << "Parsing failed\n";
			cout << "stopped at: " << info.stop->get_position().get_file() << ":" 
				 << info.stop->get_position().get_line() << "," << info.stop->get_position().get_column() 
				 << " : \" " 
				 << info.stop->get_value() << "\"\n";
			cout << "farest reached: " << info.stop.getFarest()->get_position().get_file() << ":" 
				 << info.stop.getFarest()->get_position().get_line() << "," << info.stop.getFarest()->get_position().get_column() 
				 << " : \" " 
				 << info.stop.getFarest()->get_value() << "\"\n";
			cout << "-------------------------\n";
		}
        PrintSymbols();
	}
	catch (cnome_parser_error& e)
	{
		// some preprocessing error
		std::cerr 
			<< e.where->get_position().get_file() << "(" 
			<< e.where->get_position().get_line() << ','
			<< e.where->get_position().get_column() <<"): "
			<< e.descriptor << std::endl;
		
		PrintSymbols();
		return 2;
	}
	catch (boost::wave::cpp_exception &e) 
	{
		// some preprocessing error
		std::cerr 
			<< e.file_name() << "(" << e.line_no() << "," << e.column_no() << "): "
			<< e.description() << std::endl;
		PrintSymbols();
		return 2;
	}
	catch (boost::spirit::classic::parser_error<std::string, cnome_iterator> &e)
	{
		// use last recognized token to retrieve the error position
		// some preprocessing error
		std::cerr 
			<< e.where->get_position().get_file() << "(" 
			<< e.where->get_position().get_line() << ','
			<< e.where->get_position().get_column() <<"): "
			<< e.descriptor << std::endl;
		
		PrintSymbols();
		return 3;
	}
	catch (std::exception &e) {
		// use last recognized token to retrieve the error position
		std::cerr 
			<< current_position.get_file() 
			<< "(" << current_position.get_line() << "): "
			<< "exception caught: " << e.what()
			<< std::endl;
		PrintSymbols();
		return 3;
	}
	catch (...) {
		// use last recognized token to retrieve the error position
		std::cerr 
			<< current_position.get_file() 
			<< "(" << current_position.get_line() << "): "
			<< "unexpected exception caught." << std::endl;
		PrintSymbols();
		return 4;
	}
	return 0;
}

#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#pragma warning ( default : 4996 )
#pragma warning ( default : 4800 )
#pragma warning ( default : 4355 )
#pragma warning ( default : 4267 )
#endif
